home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 12 / Mac Magazin and MacEasy Magazine CD - Issue 12.iso / Sharewarebibliothek / Anwendungen / Wissenschaft & Technik / Yorick / yorick11-nofpu folder / include / plwf.i < prev    next >
Text File  |  1995-04-03  |  8KB  |  233 lines

  1. /*
  2.    PLWF.I
  3.    Simple "painter's algorithm"-class routines for making 3-D wire frames.
  4.  
  5.    $Id: plwf.i,v 1.1 1993/08/27 18:50:06 munro Exp $
  6.  */
  7. /*    Copyright (c) 1994.  The Regents of the University of California.
  8.                     All rights reserved.  */
  9.  
  10. func plwf(z,y,x, fill=,edges=,ecolor=,ewidth=,cull=,scale=)
  11. /* DOCUMENT plwf, z
  12.          or plwf, z, y,x
  13.      plots a 3-D wire frame of the given Z array, which must have the
  14.      same dimensions as the mesh (X, Y).  The orientation of the
  15.      model can be set using the plwfset routine.  For most photogenic
  16.      results, use style="nobox.gs" in the window command, since the
  17.      projected axis ticks and labels are not very useful.
  18.      The drawing order of the zones is determined by a simple "painter's
  19.      algorithm", which works fairly well if the mesh is reasonably near
  20.      rectilinear, but can fail even then if the viewpoint is chosen to
  21.      produce extreme fisheye perspective effects.  Look at the resulting
  22.      plot carefully to be sure the algorthm has correctly rendered the
  23.      model in each case.
  24.      The viewpoint and default mesh can be set using the plwfset command.
  25.    KEYWORDS: fill   -- optional colors to use (default is to make zones
  26.                        have background color), same dimension options as
  27.                        for z argument to plf function
  28.              edges  -- default is 1 (draw edges), but if you provide fill
  29.                        colors, you may set to 0 to supress the edges
  30.              ecolor, ewidth  -- color and width of edges
  31.          cull   -- default is 1 (cull back surfaces), but if you want
  32.                    to see the "underside" of the model, set to 0
  33.          scale  -- by default, Z is scaled to "reasonable" maximum
  34.                    and minimum values related to the scale of (X,Y).
  35.                This keyword alters the default scaling factor, in
  36.                the sense that scale=2.0 will produce twice  the
  37.                Z-relief of the default scale=1.0.
  38.    SEE ALSO: plm, plf, plwfset
  39.  */
  40. {
  41.   extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
  42.   extern _plwf_theta, _plwf_phi, _plwf_psi, _plwf_vf;
  43.  
  44.   _plwf_mesh, y, x;
  45.  
  46.   /* flip z and fill into drawing order */
  47.   if (_plwf_order&1) zs= transpose(z);
  48.   else zs= z;
  49.   if (_plwf_order&2) zs= zs(::-1,);
  50.   if (_plwf_order&4) zs= zs(,::-1);
  51.   if (!is_void(fill)) {
  52.     if (_plwf_order&1) fill= transpose(fill);
  53.     if (_plwf_order&2) fill= fill(::-1,);
  54.     if (_plwf_order&4) fill= fill(,::-1);
  55.   }
  56.  
  57.   zs-= avg(zs);          /* center z at 0 */
  58.   zmax= max(zs);
  59.   sint= sin(_plwf_theta);
  60.   if (zmax && sint) {
  61.     zs/= zmax*sqrt(3)*sint;   /* guess at reasonable scale */
  62.     if (!is_void(scale)) zs*= scale;
  63.   }
  64.   xs= _plwf_x + zs*sint*cos(_plwf_phi);
  65.   ys= _plwf_y + zs*sint*sin(_plwf_phi);
  66.   zs= _plwf_z + zs*cos(_plwf_theta);
  67.  
  68.   /* (xs,ys) guaranteed to be centered at (0,0) by construction --
  69.      compute viewing distance and do perspective projection */
  70.   /* This is not really the advertised definition of viewfield,
  71.      but the real thing is very difficult to compute... */
  72.   z0= max(zs) + max(max(xs),max(ys))/_plwf_vf;
  73.   z0-= zs;   /* guaranteed positive */
  74.   xs/= z0;
  75.   ys/= z0;
  76.  
  77.   /* scale to fit into plsys,0 (NDC coordinates) */
  78.   extern _plwf_xmin, _plwf_xmax, _plwf_ymin, _plwf_ymax;
  79.   xmax= max(xs);
  80.   xmin= min(xs);
  81.   ymax= max(ys);
  82.   ymin= min(ys);
  83.   s= (_plwf_xmax-_plwf_xmin)/(xmax-xmin);
  84.   sy= (_plwf_ymax-_plwf_ymin)/(ymax-ymin);
  85.   if (s<sy) {
  86.     ox= _plwf_xmin-s*xmin;
  87.     oy= 0.5*((_plwf_ymax+_plwf_ymin)-s*(ymin+ymax));
  88.   } else {
  89.     s= sy;
  90.     oy= _plwf_ymin-s*ymin;
  91.     ox= 0.5*((_plwf_xmax+_plwf_xmin)-s*(xmin+xmax));
  92.   }
  93.   xs= s*xs+ox;
  94.   ys= s*ys+oy;
  95.  
  96.   if (is_void(edges)) edges= 1;
  97.   plf, fill, ys,xs, edges=edges,ecolor=ecolor,ewidth=ewidth;
  98. }
  99.  
  100. /* The default screen coordinates (plsys, 0) run from (.1137,.3683)
  101.    to (.6764,.9292).  If you use a landscape style, you will want
  102.    to use different coordinates.  Or use window, style="nobox.gs".  */
  103. _plwf_xmin= 0.399-0.2;
  104. _plwf_xmax= 0.399+0.2;
  105. _plwf_ymin= 0.634-0.2;
  106. _plwf_ymax= 0.634+0.2;
  107.  
  108. func plwfset(y,x, theta=,phi=,psi=, viewfield=)
  109. /* DOCUMENT plwfset, <keyword_args>
  110.          or plwfset, y,x <keyword_args>
  111.      sets the viewing angle and perspective and/or the default mesh for
  112.      the plwf command.
  113.      THETA, PHI, and PSI are Euler angles for the projection of the
  114.      model (x, y, scale*z) onto the (xs,ys) plane of the screen.
  115.      Imagine that (x,y) initially coincide with (xs,ys), with xs to
  116.      the right, ys upward, and zs out of the screen towards you.  Then
  117.      rotate the model by THETA radians about the ys-axis, so that
  118.      positive THETA would advance a right-hand screw upward (to +ys).
  119.      Next, rotate the tilted model PHI radians about the zs-axis, so
  120.      that positive PHI advances a right-hand screw towards you (to +zs).
  121.      Finally, rotate the model PSI radians about its own z-axis, again
  122.      in a right-hand sense.  The default values are THETA=acos(1/sqrt(3)),
  123.      PHI=pi/2, and PSI=pi/4, which plots Z vertically, X 30 degrees down
  124.      to the right, and y 30 degrees up to the right.  Note that PHI=pi/2
  125.      will make Z increase upwards for all sensible values of THETA.
  126.      The VIEWFIELD is the angle in radians from the center of the model
  127.      to the point which is farthest from the center, as seen from the
  128.      perspective of the viewpoint.  Small VIEWFIELD means you are looking
  129.      at the model through a telescope from a great distance; VIEWFIELD
  130.      near pi/2 is an extreme "fisheye" perspective.
  131.    SEE ALSO: plwf
  132.  */
  133. {
  134.   extern _plwf_y_d, _plwf_x_d, _plwf_z_d, _plwf_order_d;
  135.   extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
  136.   extern _plwf_theta, _plwf_phi, _plwf_psi, _plwf_vf;
  137.  
  138.   if (!is_void(theta)) _plwf_theta= theta;
  139.   if (!is_void(phi)) _plwf_phi= phi;
  140.   if (!is_void(psi)) _plwf_psi= psi;
  141.  
  142.   if (!is_void(viewfield)) {
  143.     if (viewfield<atan(0.0625)) _plwf_vf= 0.0625;
  144.     else if (viewfield>atan(12.5)) _plwf_vf= 12.5;
  145.     else _plwf_vf= tan(viewfield);
  146.   }
  147.  
  148.   /* The mesh must be set AFTER the viewing direction to allow _plwf_mesh
  149.      to properly compute the order.  */
  150.   if (!is_void(y)) {
  151.     _plwf_mesh(y, x);
  152.     _plwf_y_d= _plwf_y;
  153.     _plwf_x_d= _plwf_x;
  154.     _plwf_z_d= _plwf_z;
  155.     _plwf_order_d= _plwf_order;
  156.   }
  157. }
  158.  
  159. _plwf_theta= acos(1./sqrt(3.));
  160. _plwf_phi= 0.5*pi;
  161. _plwf_psi= 0.25*pi;
  162. _plwf_vf= 0.5;
  163.  
  164. func _plwf_mesh(y, x)
  165. {
  166.   extern _plwf_y_d, _plwf_x_d, _plwf_z_d, _plwf_order_d;
  167.   extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
  168.  
  169.   if (is_void(y)) {
  170.     _plwf_y= _plwf_y_d;
  171.     _plwf_x= _plwf_x_d;
  172.     _plwf_z= _plwf_z_d;
  173.     _plwf_order= _plwf_order_d;
  174.     return;
  175.   }
  176.  
  177.   /* The order either requires a transpose or not, reversal of the
  178.      order of the first dimension or not, and reversal of the order
  179.      of the second dimension or not.  */
  180.  
  181.   /* rotate (x,y,0) into on-screen orientation to determine order */
  182.   xs2=      x*cos(_plwf_psi)-y*sin(_plwf_psi);
  183.   _plwf_y=  y*cos(_plwf_psi)+x*sin(_plwf_psi);
  184.   _plwf_z= -xs2*sin(_plwf_theta);
  185.   xs2*=         cos(_plwf_theta);
  186.   _plwf_x= xs2*cos(_plwf_phi)-_plwf_y*sin(_plwf_phi);
  187.   _plwf_y= _plwf_y*cos(_plwf_phi)+xs2*sin(_plwf_phi);
  188.  
  189.   /* compute mean i-edge and j-edge vector z-components */
  190.   iedge= avg(_plwf_z(dif,));
  191.   jedge= avg(_plwf_z(,dif));
  192.  
  193.   /* The direction with the minimum magnitude average z-component must
  194.      vary fastest in the painting order.  If this is the j-direction,
  195.      a transpose will be required to make this the i-direction.  */
  196.   if (_plwf_order= abs(jedge)<abs(iedge)? 1 : 0) {
  197.     tmp= iedge;   iedge= jedge;   jedge= tmp;
  198.     _plwf_x= transpose(_plwf_x);
  199.     _plwf_y= transpose(_plwf_y);
  200.     _plwf_z= transpose(_plwf_z);
  201.   }
  202.  
  203.   /* Zones must be drawn from back to front, which means that the
  204.      average z-component of the edge vectors must be positive.  This
  205.      can be arranged by reversing the order of the elements if
  206.      necessary.  */
  207.   if (iedge<0.0) {
  208.     _plwf_order|= 2;
  209.     _plwf_x= _plwf_x(::-1,);
  210.     _plwf_y= _plwf_y(::-1,);
  211.     _plwf_z= _plwf_z(::-1,);
  212.   }
  213.   if (jedge<0.0) {
  214.     _plwf_order|= 4;
  215.     _plwf_x= _plwf_x(,::-1);
  216.     _plwf_y= _plwf_y(,::-1);
  217.     _plwf_z= _plwf_z(,::-1);
  218.   }
  219.  
  220.   /* put center of mesh at (0,0) in screen coordinates */
  221.   _plwf_x-= avg(_plwf_x);
  222.   _plwf_y-= avg(_plwf_y);
  223.   _plwf_z-= avg(_plwf_z);
  224.  
  225.   /* normalize mesh so that biggest dimension is 1.0 */
  226.   xmax= max(_plwf_x);
  227.   ymax= max(_plwf_y);
  228.   if (ymax>xmax) xmax= ymax;
  229.   _plwf_x/= xmax;
  230.   _plwf_y/= xmax;
  231.   _plwf_z/= xmax;
  232. }
  233.